package com.gopay.bis.pab.ebank.operation;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.zookeeper.Login;

import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.exception.GopayException;
import com.gopay.remote.bank.ICertHelper;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * 平安银行 签名/验签工具类
 * 
 *
 * @author 宣广海
 *
 * @version
 *
 * @since 2016年4月13日
 */
public class PabB2cCerthelper implements ICertHelper {
	private static Log logger = LogFactory.getLog(PabB2cCerthelper.class);

	/**
	 * 签名
	 * 
	 * @param Object
	 *            plainText
	 * @return Object
	 * @throws GopayException
	 */
	public String sign(BaseMessage bsaeMessage) throws GopayException {
		try {
			BankLogUtils.printB2CSignPlainLog(bsaeMessage);
			byte[] plainMessage = bsaeMessage.getPlainMessage().getBytes();
			String signMessage = signData(plainMessage, bsaeMessage.getPrivateKeyPath(), bsaeMessage.getPrivatePwd());
			BankLogUtils.printB2CSignSignatureLog(bsaeMessage, signMessage);
			return signMessage;
		} catch (Exception e) {
			BankLogUtils.printB2CSignExceptionLog(bsaeMessage, e);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6029);
		}
	}

	/**
	 * 验签
	 * 
	 * @param Object
	 *            plainText
	 * @param Object
	 *            signature
	 * @return Object
	 * @throws GopayException
	 */
	public Object verify(BaseMessage bsaeMessage) throws GopayException {
		try {
			String signSrcMessage=bsaeMessage.getSignMessage().trim();
			String plainMessage = bsaeMessage.getPlainMessage().trim();
			boolean verifyFlag=verifyData(plainMessage.getBytes(),new BASE64Decoder().decodeBuffer(signSrcMessage),bsaeMessage.getPublicKeyPath());
			BankLogUtils.printB2CVerifyPlainLog(bsaeMessage);
			BankLogUtils.printB2CVerifySignatureLog(bsaeMessage, bsaeMessage.getSignMessage());
			BankLogUtils.printB2CVerifyResultLog(bsaeMessage, verifyFlag);
			return verifyFlag;
		} catch (Exception e) {
			BankLogUtils.printB2CSignExceptionLog(bsaeMessage, e);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6031);
		}
	}

	/**
	 * 
	 * 功能描述：根据原数据和指定的加密算法来生成用户的签名数据
	 *
	 * @param srcData：被签名数据，byte[]类型
	 * @param path：商户私钥jks文件存放路径
	 * @param pwd:商户私钥密码
	 * @return 已签名数据
	 * @throws GopayException
	 * 
	 * @author 宣广海
	 *
	 * @since 2016年4月13日
	 *
	 * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
	 */
	public String signData(byte[] srcData, String path, String pwd) throws GopayException {
		logger.info("path="+path);
		logger.info("pwd="+pwd);
		FileInputStream stream = null;
		try {
			/**
			 * 获取JKS 服务器私有证书的私钥，取得标准的JKS的 KeyStore实例
			 */
			KeyStore store = KeyStore.getInstance("JKS");
			logger.info("1="+1);
			/**
			 * 读取jks文件，path为商户私钥jks文件存放路径
			 */
			stream = new FileInputStream(path);
			logger.info("2="+2);
			/**
			 * jks文件密码，根据实际情况修改
			 */
			String passwd = pwd;
			store.load(stream, passwd.toCharArray());
			
			/**
			 * 获取jks证书别名
			 */
			Enumeration en = store.aliases();
			String pName = null;
			while (en.hasMoreElements()) {
				String n = (String) en.nextElement();
				if (store.isKeyEntry(n)) {
					pName = n;
				}
			}

			/**
			 * 获取证书的私钥
			 */
			PrivateKey key = (PrivateKey) store.getKey(pName, passwd.toCharArray());
			logger.info("3="+3);
			/**
			 * 进行签名服务
			 */
			Signature signature = Signature.getInstance("SHA1withRSA");
			signature.initSign(key);
			signature.update(srcData);
			byte[] signedData = signature.sign();

			/**
			 * 返回签名结果
			 */
			return new BASE64Encoder().encode(signedData);
		} catch (Exception e) {
			e.printStackTrace();
			logger.info("========"+e);
			throw new GopayException();
		} finally {
			if (null != stream) {
				try {
					stream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 根据对签名数据使用签名者的公钥来解密后验证是否与原数据相同。从而确认用户签名正确
	 * 
	 * @param 使用的加密算法，需与加密时使用的算法一致
	 * @param srcData
	 *            被签名数据，byte[]类型
	 * @param signedData
	 *            使用该用户的私钥生成的已签名数据
	 * @param path商户公钥证书cer文件存放路径
	 * @return true或false，验证成功为true。
	 * @throws Exception
	 */
	public boolean verifyData(byte[] srcData, byte[] signedData, String path) throws GopayException { 
		try {
			/**
			 * 进行验证签名服务
			 */
			logger.info("srcData="+new String(srcData));
			logger.info("signedData="+new String(signedData));
			logger.info("path="+path);
			CertificateFactory certInfo = CertificateFactory.getInstance("x.509");
			X509Certificate cert = (X509Certificate) certInfo.generateCertificate(new FileInputStream(path));
			PublicKey publicKey = cert.getPublicKey();
			Signature sign3 = Signature.getInstance("SHA1withRSA");
			sign3.initVerify(publicKey);
			sign3.update(srcData);
			return sign3.verify(signedData);
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
			throw new GopayException();
		}
	}

}
